#include "element_proxy.h"

#include <iostream>

namespace tinyndarray {
// ==================== ConstElementProxy 实现 ====================
// ConstElementProxy::ConstElementProxy(const void* ptr, Dtype dtype) : ptr()(ptr), dtype()(dtype) {}

// ConstElementProxy::operator float32_t() const {
//     if (dtype().tag != FP32) throw std::runtime_error("Type mismatch: not a float");
//     return *static_cast<const float32_t*>(ptr());
// }

// ConstElementProxy::operator int() const {
//     if (dtype().tag != INT32) throw std::runtime_error("Type mismatch: not an int");
//     return *static_cast<const int*>(ptr());
// }

// ConstElementProxy::operator float64_t() const {
//     if (dtype().tag != FP64) throw std::runtime_error("Type mismatch: not a double");
//     return *static_cast<const float64_t*>(ptr());
// }

// ConstElementProxy::operator bool() const {
//     if (dtype().tag != BOOL) throw std::runtime_error("Type mismatch: not a bool");
//     return *static_cast<const bool*>(ptr());
// }

// std::ostream& operator<<(std::ostream& os, const ConstElementProxy& proxy) {
//     switch (proxy.dtype().tag) {
//         case FP32: os << *static_cast<const float*>(proxy.ptr()); break;
//         case INT32: os << *static_cast<const int*>(proxy.ptr()); break;
//         case FP64: os << *static_cast<const double*>(proxy.ptr()); break;
//         case BOOL: os << std::boolalpha << *static_cast<const bool*>(proxy.ptr()); break;
//         default: os << "?";
//     }
//     return os;
// }

ElementProxy& ElementProxy::operator=(const ElementProxy& other) {
    if (this != &other) {
        switch (dtype().tag) {
            case FP32: *static_cast<float*>(ptr()) = *static_cast<const float*>(other.ptr()); break;
            case INT32: *static_cast<int*>(ptr()) = *static_cast<const int*>(other.ptr()); break;
            case FP64: *static_cast<double*>(ptr()) = *static_cast<const double*>(other.ptr()); break;
            case BOOL: *static_cast<bool*>(ptr()) = *static_cast<const bool*>(other.ptr()); break;
            default: throw std::runtime_error("Unsupported data type for copy assignment");
        }
    }
    return *this;
}

ElementProxy& ElementProxy::operator=(float32_t value) {
    if (dtype().tag != FP32) throw std::runtime_error("Cannot assign float to non-float element");
    *static_cast<float32_t*>(ptr()) = value;
    return *this;
}

ElementProxy& ElementProxy::operator=(int32_t value) {
    if (dtype().tag != INT32) throw std::runtime_error("Cannot assign int to non-int element");
    *static_cast<int32_t*>(ptr()) = value;
    return *this;
}

ElementProxy& ElementProxy::operator=(float64_t value) {
    if (dtype().tag != FP64) throw std::runtime_error("Cannot assign double to non-double element");
    *static_cast<float64_t*>(ptr()) = value;
    return *this;
}

ElementProxy& ElementProxy::operator=(bool value) {
    if (dtype().tag != BOOL) throw std::runtime_error("Cannot assign double to non-bool element");
    *static_cast<bool*>(ptr()) = value;
    return *this;
}

void ElementProxy::reset(void* ptr, Dtype dtype) {
    set_ptr(ptr);
    set_dtype(dtype);
}

std::ostream& operator<<(std::ostream& os, const ElementProxy& proxy) {
    switch (proxy.dtype().tag) {
        case QINT8: os << *static_cast<const int8_t*>(proxy.ptr()); break;
        case QUINT8: os << *static_cast<const uint8_t*>(proxy.ptr()); break;
        case INT32: os << *static_cast<const int32_t*>(proxy.ptr()); break;
        case FP32: os << *static_cast<const float32_t*>(proxy.ptr()); break;
        case FP64: os << *static_cast<const float64_t*>(proxy.ptr()); break;
        case BOOL: os << std::boolalpha << *static_cast<const bool*>(proxy.ptr()); break;
        default: os << "?";
    }
    return os;
}
}  // namespace tinyndarray